package com.cniao5.common

import kotlinx.coroutines.*
import org.junit.Test
import kotlin.system.measureTimeMillis

/**
 * @description: kotlin协程示例
 * @author HaolinLv
 * @date :2022/2/11 17:05
 */

class KtCoroutinesTest {
    //region    基础函数
    @Test
    fun testKtCoroutines() {

//        testLaunch()
//        launch相当于android的service，只管开始，不管有没有运行完毕

//        testLaunchWithoutSleep()

//        testAsync()
//        Async相当于启动两个异步协程，可以获得返回结果

//        testRunBlocing()

//        testCancelJoin()

        testAwait()
    }

    /**
     * 1.异步，不阻塞线程
     * CoroutinesScope.launch具有生命周期
     */
    private fun testLaunch() {
        val time: Long = measureTimeMillis {  //测量函数耗时
            //启动两个协程
            GlobalScope.launch {
                Thread.sleep(1000)
                //打印当前线程
                println("testLaunch的Launch中, ${Thread.currentThread()} 我很好")
            }
            GlobalScope.launch {
                Thread.sleep(1000)
                println("testLaunch的Launch中, ${Thread.currentThread()} 嘿嘿嘿🤭")
            }
            println("你好么 ${Thread.currentThread()}")
            Thread.sleep(2200)
        }
        println("函数总耗时：$time")

        /*函数执行结果：
            你好么 Thread[main,5,main]
            testLaunch的Launch中, Thread[DefaultDispatcher-worker-2 @coroutine#2,5,main] 嘿嘿嘿🤭
            testLaunch的Launch中, Thread[DefaultDispatcher-worker-3 @coroutine#1,5,main] 我很好
            函数总耗时：2299
         */
    }

    private fun testLaunchWithoutSleep() {
        val time: Long = measureTimeMillis {  //测量函数耗时
            //在一个线程里面启动两个协程，执行顺序不固定，由CPU调度
            GlobalScope.launch {
                Thread.sleep(1000)
                //打印当前线程
                println("testLaunch的Launch中, ${Thread.currentThread()} 我很好")
            }
            GlobalScope.launch {
                Thread.sleep(1000)
                println("testLaunch的Launch中, ${Thread.currentThread()} 嘿嘿嘿🤭")
            }
            println("你好么 ${Thread.currentThread()}")
//            Thread.sleep(2200)
        }
        println("函数总耗时：$time")

        /*函数执行结果：
            //协程还没执行完毕，jvm就销毁了函数栈
            你好么 Thread[main,5,main]
            函数总耗时：0
         */

    }

    /**
     * 2.Async，异步，不阻塞线程
     * CoroutinesScope.Async具有生命周期
     */
    private fun testAsync() {
        val time: Long = measureTimeMillis {  //测量函数耗时
            //启动两个协程,和launch的区别：返回数据类型不一样
            GlobalScope.async {
                Thread.sleep(1000)
                //打印当前线程
                println("testLaunch的async中, ${Thread.currentThread()} 我很好")
            }
            GlobalScope.async {
                Thread.sleep(1000)
                println("testLaunch的async2中, ${Thread.currentThread()} 嘿嘿嘿🤭")
            }
            println("你好么 ${Thread.currentThread()}")
            Thread.sleep(2200)
        }
        println("函数总耗时：$time")
    }

    /**
     * 3.runBlocking 阻塞线程
     * 桥接普通函数和协程
     */
    private fun testRunBlocing() {
        val time: Long = measureTimeMillis {
            //创建一个带阻塞的协程生命周期
            runBlocking {
                //顺序执行，先block1，后block2
                println("testRunBlocking的block中 ${Thread.currentThread()} before delay")
                delay(500)
                println("testRunBlocking的block2中 ${Thread.currentThread()} ———after delay———")
            }
            println("testRunBlocking ${Thread.currentThread()} hello")
        }
        //必须先运行完blocking，再执行下一步普通函数
        println("函数总耗时：$time")

        /*执行结果：
            testRunBlocking的block中 Thread[main @coroutine#7,5,main] before delay
            testRunBlocking的block中 Thread[main @coroutine#7,5,main] ———after delay———
            //因为协程为阻塞的生命周期，所以先执行协程，再执行普通函数
            testRunBlocking Thread[main,5,main] hello
            函数总耗时：521
         */
    }

    /**
     * 4.cancel join
     * runBlocking会等待内部的协程执行完毕再结束，对比test1的jvm
     * 异步的特性，注意执行输出的结果
     */
    private fun testCancelJoin() = runBlocking {
        val time: Long = measureTimeMillis {
            val L1: Job = launch {
                println("testCancelJoinTimeOut>>Launch1 ${Thread.currentThread()} L1 Hello")
            }
            val L2: Job = launch {
                println("testCancelJoinTimeOut>>Launch2 ${Thread.currentThread()} L2 Hello")
            }
            //Deferred是Job的子接口
            val a2: Deferred<Unit> = async {
                repeat(20) {
                    println("testCancelJoinTimeOut>>Async2 ${Thread.currentThread()} $it a2 Hello")
                    delay(200)
                }
            }
            //a2加入到runBlocking,如此则必须a2结束协程才会走下面的
//            a2.join()

            val a1: Deferred<Unit> = async {
                println("testCancelJoinTimeOut>>Async1 ${Thread.currentThread()} a1 Hello")
                //测试取消 a2
                a2.cancel()
            }
            println("testCancelJoinTimeOut ${Thread.currentThread()} 外部")
        }

        println("函数总耗时：$time")

        /*执行结果：
        testCancelJoinTimeOut Thread[main @coroutine#1,5,main] 外部
        函数总耗时：15
        //不一定顺序执行
        testCancelJoinTimeOut>>Launch1 Thread[main @coroutine#2,5,main] L1 Hello
        testCancelJoinTimeOut>>Launch2 Thread[main @coroutine#3,5,main] L2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 0 a2 Hello
        testCancelJoinTimeOut>>Async1 Thread[main @coroutine#5,5,main] a1 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 1 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 2 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 3 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 4 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 5 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 6 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 7 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 8 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 9 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 10 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 11 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 12 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 13 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 14 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 15 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 16 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 17 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 18 a2 Hello
        testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 19 a2 Hello
         */

        /* a2.join执行结果：
            testCancelJoinTimeOut>>Launch1 Thread[main @coroutine#2,5,main] L1 Hello
            testCancelJoinTimeOut>>Launch2 Thread[main @coroutine#3,5,main] L2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 0 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 1 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 2 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 3 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 4 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 5 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 6 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 7 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 8 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 9 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 10 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 11 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 12 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 13 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 14 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 15 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 16 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 17 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 18 a2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 19 a2 Hello
            testCancelJoinTimeOut Thread[main @coroutine#1,5,main] 外部
            函数总耗时：4207
            testCancelJoinTimeOut>>Async1 Thread[main @coroutine#5,5,main] a1 Hello
         */

        /* a2.cancel执行结果：
            testCancelJoinTimeOut Thread[main @coroutine#1,5,main] 外部
            函数总耗时：22
            testCancelJoinTimeOut>>Launch1 Thread[main @coroutine#2,5,main] L1 Hello
            testCancelJoinTimeOut>>Launch2 Thread[main @coroutine#3,5,main] L2 Hello
            testCancelJoinTimeOut>>Async2 Thread[main @coroutine#4,5,main] 0 a2 Hello
            testCancelJoinTimeOut>>Async1 Thread[main @coroutine#5,5,main] a1 Hello
         */

    }

    private fun testTimeOut() = runBlocking {
        val time2: Long = measureTimeMillis {
            //超时自动结束内部协程并抛出异常
            withTimeout(3000) {
                launch {
                    repeat(200) {
                        println("withTimeOut中 launch 的 ${Thread.currentThread()} $it")
                        delay(300)
                    }
                }
                println("WithTimeOut ${Thread.currentThread()}")
            }
            //超时结束我，但不会抛出异常
            withTimeoutOrNull(1000) {

            }
        }
    }

    /**
     * await，async的异步结果获取
     */
    private fun testAwait() = runBlocking {
        val time: Long = measureTimeMillis {
            val a2: Deferred<Int> = async {
                println("testAwait ${Thread.currentThread()} A2 hello")
                delay(3000)
                100 //返回async值100到a2
            }
            val a1: Deferred<Int> = async {
                println("testAwait ${Thread.currentThread()} A1 hello")
                delay(2000)
                99 //返回async值100到a2
//                getA1()
            }
            //await:挂起协程，等待执行结果，不会阻塞
            println("结果 ${Thread.currentThread()} —— ${a1.await()} —— ${a2.await()}")
            //会报错，执行此语句时a1，a2还没执行完，没有值；a1，a2 join到runBlocking，才不会报错
//            println("结果 ${Thread.currentThread()} —— ${a1.getCompleted()} —— ${a2.getCompleted()}")

        }
        println("函数耗时： $time")

        /*执行结果：（a1，a2不join，await打印）
            testAwait Thread[main @coroutine#2,5,main] A2 hello
            testAwait Thread[main @coroutine#3,5,main] A1 hello
            结果 Thread[main @coroutine#1,5,main] —— 99 —— 100
            函数耗时： 3029
         */
    }

    private suspend fun getA1(): Int {
        println("testAwait>>async ${Thread.currentThread()} A1 hello")
        delay(2000)
        return 99
    }

    //endregion


}